package cc.shacocloud.mirage.restful;

import cc.shacocloud.mirage.restful.bind.WebDataBinderFactory;
import cc.shacocloud.mirage.utils.LogFormatUtils;
import cc.shacocloud.mirage.utils.MethodParameter;
import cc.shacocloud.mirage.utils.collection.ArrayUtil;
import io.vertx.core.Future;
import io.vertx.core.buffer.Buffer;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * 扩展了 {@link InvocableHandlerMethod}，使其能够通过已注册的{@link HandleMethodReturnValueHandler}处理返回值。
 */
@Slf4j
public class VertxInvocableHandlerMethod extends InvocableHandlerMethod implements VertxInvokeHandler {
    
    @Setter
    @Nullable
    private HandleMethodReturnValueHandlerComposite returnValueHandlers;
    
    @Setter
    @Nullable
    private WebDataBinderFactory webDataBinderFactory;
    
    public VertxInvocableHandlerMethod(Object handler, Method method) {
        super(handler, method);
    }
    
    public VertxInvocableHandlerMethod(HandlerMethod handlerMethod) {
        super(handlerMethod);
    }
    
    /**
     * 调用方法并通过配置的{@link HandleMethodReturnValueHandlerComposite}来处理返回值。
     */
    @Override
    public Future<Object> invokeAndHandleRoutingContext(RoutingContext routingContext, Object... providedArgs) {
        return invokeAndHandleHandlerMethod(routingContext, createWithResolvedBean(), providedArgs);
    }
    
    @Override
    public Future<Object> invokeAndHandleHandlerMethod(RoutingContext routingContext,
                                                       HandlerMethod handlerMethod,
                                                       Object... providedArgs) {
        if (this.returnValueHandlers == null) {
            throw new IllegalStateException("未设置结果值处理器！");
        }
        
        HttpRequest request = routingContext.request();
        HttpResponse response = routingContext.response();
        
        // 合并参数
        Object[] mergeProvidedArgs;
        if (ArrayUtil.isNotEmpty(providedArgs)) {
            mergeProvidedArgs = Arrays.copyOf(providedArgs, providedArgs.length + 3);
            System.arraycopy(new Object[]{routingContext, request, response}, 0, mergeProvidedArgs, providedArgs.length, 3);
        } else {
            mergeProvidedArgs = new Object[]{routingContext, request, response};
        }
        
        try {
            // 执行请求
            InvocableHandlerMethod invocableHandlerMethod = createInvocableHandlerMethodAndCopyProperty(handlerMethod);
            return invocableHandlerMethod.invokeForRequest(request, webDataBinderFactory, mergeProvidedArgs).map(r -> r);
        } catch (Exception e) {
            return Future.failedFuture(e);
        }
    }
    
    @Override
    public Future<Buffer> resultHandle(Object result, HttpResponse response) {
        return resultHandle(result, createWithResolvedBean(), response);
    }
    
    @Override
    public Future<Buffer> resultHandle(Object result,
                                       HandlerMethod handlerMethod,
                                       HttpResponse response) {
        if (this.returnValueHandlers == null) {
            throw new IllegalStateException("未设置结果值处理器！");
        }
        
        if (result != null && !Void.TYPE.equals(result.getClass())) {
            
            if (log.isDebugEnabled()) {
                log.debug("解析处理器方法 [" + handlerMethod + "] 的执行结果 : [" + LogFormatUtils.formatValue(result, false) + "]");
            }
            
            try {
                // 处理返回结果
                MethodParameter returnValueType = handlerMethod.getReturnValueType(result);
                return this.returnValueHandlers.handleReturnValue(response, returnValueType, result);
            } catch (Exception ex) {
                if (log.isDebugEnabled()) {
                    log.debug(formatErrorForReturnValue(result), ex);
                }
                return Future.failedFuture(ex);
            }
        }
        
        return Future.succeededFuture();
    }
    
    @Override
    public Object getHandler() {
        return createWithResolvedBean();
    }
    
    @NotNull
    private String formatErrorForReturnValue(@Nullable Object returnValue) {
        return "处理返回值=[" + returnValue + "]时出错" +
                (returnValue != null ? ", 类型=" + returnValue.getClass().getName() : "") + " 为 " + this;
    }
    
    protected InvocableHandlerMethod createInvocableHandlerMethodAndCopyProperty(HandlerMethod handlerMethod) {
        if (handlerMethod == this) return this;
        
        InvocableHandlerMethod invocableHandlerMethod = handlerMethod instanceof InvocableHandlerMethod
                ? (InvocableHandlerMethod) handlerMethod
                : new InvocableHandlerMethod(handlerMethod);
        
        invocableHandlerMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
        invocableHandlerMethod.setHandlerMethodArgumentResolvers(this.resolvers);
        
        return invocableHandlerMethod;
    }
    
}
